package com.warehouse.module.business.service.cargoplan;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.warehouse.framework.common.pojo.PageResult;
import com.warehouse.module.business.controller.admin.cargoinfo.vo.CargoInfoRespVO;
import com.warehouse.module.business.controller.admin.cargoplan.vo.CancelPlanVO;
import com.warehouse.module.business.controller.admin.cargoplan.vo.CargoPlanExcelRespVO;
import com.warehouse.module.business.controller.admin.cargoplan.vo.CargoPlanPageReqVO;
import com.warehouse.module.business.convert.cargoplan.CargoPlanConvert;
import com.warehouse.module.business.dal.dataobject.cargoinfo.CargoInfoDO;
import com.warehouse.module.business.dal.dataobject.cargoplan.CargoPlanDO;
import com.warehouse.module.business.dal.mysql.cargoinfo.CargoInfoMapper;
import com.warehouse.module.business.dal.mysql.cargoplan.CargoPlanMapper;
import com.warehouse.module.business.enums.OrderStatusEnum;
import com.warehouse.module.business.enums.PlanStatusEnum;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

import static com.warehouse.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.warehouse.module.business.enums.ErrorCodeConstants.*;

@Service
@Validated
public class CargoPlanServiceImpl implements CargoPlanService {

    @Resource
    private CargoPlanMapper cargoPlanMapper;
    @Resource
    private CargoInfoMapper cargoInfoMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addPlan(CargoPlanDO cargoPlanDO) {
        cargoPlanMapper.insert(cargoPlanDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editPlan(CancelPlanVO cancelPlanVO) {

        CargoPlanDO planDO = cargoPlanMapper.selectById(cancelPlanVO.getId());
        String cargoIds = planDO.getCargoIds();
        List<Long> ids = Arrays.stream(cargoIds.split(",")).map(it->Convert.toLong(it)).collect(Collectors.toList());
        for(Long cargoId : cancelPlanVO.getCargoIds()){
            CargoInfoDO infoDO = cargoInfoMapper.selectById(cargoId);
            if(infoDO.getStorage()==1 && !infoDO.getStatus().equals(OrderStatusEnum.PENDING_RELEASE.getStatus())){
                throw exception(CARGO_INFO_PLAN_BACK_ERR);
            }else if(infoDO.getStorage() == 0 && !infoDO.getStatus().equals(OrderStatusEnum.PENDING_CHECK.getStatus())){
                throw exception(CARGO_INFO_PLAN_BACK_ERR);
            }
            if(ids.indexOf(cargoId) > -1){
                ids.remove(cargoId);
            }else{
                throw exception(CARGO_INFO_PLAN_BACK_ERR);
            }
        }

        if(ids.size() > 0){
            planDO.setCargoIds(String.join(",", ids.stream().map(it->it.toString()).collect(Collectors.toList())));
            cargoPlanMapper.updateById(planDO);
        }else{
            cargoPlanMapper.deleteById(cancelPlanVO.getId());
        }

        LambdaUpdateWrapper<CargoInfoDO> updateWrapper = Wrappers.lambdaUpdate(CargoInfoDO.class)
                .in(CargoInfoDO::getId, cancelPlanVO.getCargoIds())
                .set(CargoInfoDO::getPlanStatus, PlanStatusEnum.PENDING_PLANING.getStatus());
        cargoInfoMapper.update(updateWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void backPlan(CancelPlanVO cancelPlanVO) {

        CargoPlanDO planDO = cargoPlanMapper.selectById(cancelPlanVO.getId());
        String cargoIds = planDO.getCargoIds();
        List<Long> ids = Arrays.stream(cargoIds.split(",")).map(it->Convert.toLong(it)).collect(Collectors.toList());
        for(Long cargoId : cancelPlanVO.getCargoIds()){
            if(ids.indexOf(cargoId) > -1){
                ids.remove(cargoId);
            }else{
                throw exception(CARGO_INFO_PLAN_BACK_ERR);
            }
        }

        if(ids.size() > 0){
            planDO.setCargoIds(String.join(",", ids.stream().map(it->it.toString()).collect(Collectors.toList())));
            cargoPlanMapper.updateById(planDO);
        }else{
            cargoPlanMapper.deleteById(cancelPlanVO.getId());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delPlan(Long id) {
        cargoPlanMapper.deleteById(id);
    }

    @Override
    public CargoPlanDO getByCargoId(Long cargoId) {
        LambdaQueryWrapper<CargoPlanDO> query = Wrappers.lambdaQuery(CargoPlanDO.class)
                .apply(StrUtil.format("find_in_set({}, cargo_ids) > 0", cargoId));
        return cargoPlanMapper.selectOne(query);
    }

    @Override
    public PageResult<CargoPlanDO> pageCargoPlans(CargoPlanPageReqVO req){
        return cargoPlanMapper.selectPage(req);
    }

    @Override
    public List<CargoInfoRespVO> listCargoInfosByPlanId(Long id){
        return cargoPlanMapper.listCargoInfosByPlanId(id);
    }

    @Override
    public List<CargoPlanExcelRespVO> getCargoPlanExcel(Long id) {
        List<CargoInfoRespVO> list = this.listCargoInfosByPlanId(id);
        return CargoPlanConvert.INSTANCE.convertList(list);
    }
}
